Принципы объектно-ориентированного программирования

         

Web-узлы и Web-службы, работающие на основе ATL Server

Создавать Web-приложения и Web-службы можно несколькими способами Один из них — это использовать технологию ASP NET Такой подход поддерживается в разной степени большинством языков платформы NET Есть и другой подход, поддерживаемый только языком Visual C++ Он состоит в применении сервера ATL Server [ATL Server реализован с помощью неуправляемого C++ и поэтому не относится к основной предметной области NET Впрочем, для некоторых программистов, работающих на Visual C++ ATL является достаточно важной темой]. Остальные, традиционные подходы заключаются в использовании общего шлюзового интерфейса CGI (Common Gateway Interface), и интерфейса прикладного программирования Internet-сервера ISAPI Преимуществом технологии ASP NET являются простота и легкость в использовании Кроме того, поддержка этой технологии несколькими языками означает, что она доступна большему числу программистов и на большем количестве уровней квалификации. Что же касается технологии ATL Server, то ее преимущество состоит в более высокой производительности, чем у ASP NET
Конечно, работать с ATL Server намного легче, чем с традиционной технологией Web-разработки, реализуемой на основе C++ и называемой интерфейсом прикладного программирования Internet-сервера ISAPI (Internet Services API — API Internet-служб,


т е интерфейс прикладного программирования Internet-служб) Однако от программиста технология ATL Server требует больше опыта, чем ASP NET Обычно использование ATL Server не исключает применения ASP NET и наоборот Часто бывает так, что их возможности приходится комбинировать И поскольку с библиотекой шаблонных классов ATL работать труднее, то в большинстве ваших Web-проектов, возможно, придется использовать ASP NET А где найти применение библиотеке шаблонных классов ATL9 Она может пригодиться в тех нескольких областях, где по-настоящему требуется максимальная производительность.

История технологий, работающих с динамическим содержимым Web

До сегодняшнего дня было немало методик работы с динамическим содержимым Web. Самой старой из них, которая поддерживается большинством HTTP-серверов, является общий шлюзовой интерфейс (CGI). С помощью переменных среды, CGI-программа принимает данные заголовка HTTP-запроса, отправляемые с Web-броузера. Кроме того, такая программа, пользуясь перенаправленным стандартным входным потоком, принимает данные запроса через Web-сервер, а затем генерирует динамический HTML для передачи клиенту через тот же Web-сервер, используя перенаправленный стандартный выходной поток. Конечно, применение переменных среды, стандартных входного и выходного потоков является способом не слишком эффективным, зато работающим одинаково на большинстве Web-серверов, размещенных как в Unix, так и в Windows. К сожалению, для каждого клиентского запроса общий шлюзовой интерфейс (CGI) создает новый процесс, а это слишком дорого обходится с точки зрения производительности и использования ресурсов. Так что эффективно обработать большое количество клиентских запросов с помощью общего шлюзового интерфейса (CGI) не удается. К тому же, Web-сервер и CGI-процесс находятся в разных адресных пространствах. Поэтому общий шлюзовой интерфейс (CGI) страдает еще и от накладных расходов, вызываемых большим количеством взаимодействий между процессами.
Что касается интерфейса прикладного программирования Internet-сервера ISAPI, который представляет собой технологию на основе информационного сервера Internet (Internet Information Server, US), то он решает проблемы с производительностью и масштабированием, выполняя вместо CGI-процесса встроенную в процесс динамически подсоединяемую библиотеку (DLL) интерфейса прикладного программирования Internet-сервера (ISAPI), По требованию эта библиотека загружается в адресное пространство информационного сервера Internet (IIS) и совместно используется многими W/eb-клиентами. Интерфейс прикладного программирования Internet-сервера (ISAPI) содержит интерфейсы прикладного программирования (API), которые необходимы для доступа к клиентским запросам, и, в частности, ко входным параметрам и HTTP-заголовкам. Для чтения данных, находящихся в запросах, интерфейс прикладного программирования Internet-сервера (ISAPI) организует входной поток, а для отправки клиенту, в ответ на его запрос, динамически созданного HTML-кода — выходной поток. Такой подход намного эффективнее, чем использование общего шлюзового интерфейса CGI, потому что новый процесс не создается, и, следовательно, взаимодействие процессов на сервере не требуется. В среде Visual C++ 6.0 имеется ISAPI Extension Wizard (Мастер создания расширений интерфейса прикладного программирования Internet-сервера), предназначенный для создания на основе MFC расширений интерфейса прикладного программирования Internet-сервера. Кроме того, там имеются проекты фильтров для интерфейса прикладного программирования Internet-сервера (ISAPI). Для работы с интерфейсом прикладного программирования Internet-сервера (ISAPI) в библиотеке MFC предусмотрен CHttpServer, исполняющий роль оболочки в интерфейсе прикладного программирования Internet-служб, а также макрос для создания карты сообщений и макросы для различных преобразований в ходе грамматического разбора.
Фильтры и расширения интерфейса прикладного программирования Internet-сервера (ISAPI) прекрасно подходили для создания высокопроизводительных Web-приложений, однако требовали от программистов достаточно высокой квалификации. Этим специалистам нужно было не только знать C++, но также понимать и использовать организацию пула с помощью процессов, синхронизацию, обработку транзакций и безопасность. Помимо этого, программисту требовалось быть очень осторожным и перед размещением динамически подсоединяемой библиотеки (DLL) интерфейса прикладного программирования Internet-сервера (ISAPI), приходилось проводить большое количество испытанийСДёло в том, что любая достаточно серьезная ошибка в такой библиотеке, работающей в рамках того же процесса, что и информационный сервер Internet, привела бы к аварийному завершению всего процесса (то есть к аварийному завершению работы Web-сервера OS). И, наконец, большинство программистов возненавидело интерфейс прикладного программирования Internet-сервера (ISAPI). Причина здесь в том, что фильтры и расширения интерфейса прикладного программирования Internet-сервера (ISAPI) труднее поддаются отладке, чем другие программы, написанные на C++, так как необходимо подсоединяться к работающему процессу, в рамках которого выполняется информационный сервер Internet (П5).
Что касается технологии ASP, то для разработки на высоком уровне динамического Web-содержимого она является достаточно удобным средством. Эта технология использует интерфейс прикладного программирования Internet-сервера (ISAPI), но при этом не столь эффективна, как интерфейс прикладного программирования Internet-сервера (ISAPI) в чистом виде. ASP фактически реализована в виде заранее подготовленной, достаточно универсальной динамически подсоединяемой библиотеки (DLL) интерфейса прикладного программирования Internet-сервера (ISAPI), которая реализует машину сценариев. В свою очередь машина сценариев потом интерпретирует ASP-страницу. Такая страница похожа на обычную HTML-страницу, за исключением того, что содержит встроенные фрагменты ASP-кода, написанные в виде сценария. Этот код не компилируется, а интерпретируется машиной сценариев. Для интерпретации можно использовать любой язык подготовки сценариев, который установлен на Web-сервере, поддерживающем ASP. По умолчанию информационный сервер Internet (П5) автоматически поддерживает VBScript и JScript. Недостатком ASP является то, что интерпретируемый код, естественно, работает медленнее, чем выполняющий те же действия скомпилированный код, в котором используется интерфейс прикладного программирования Internet-сервера (ISAPI).
Другим недостатком ASP является то, что языки подготовки сценариев не обеспечивают типовую безопасность, что может привести к ошибкам времени выполнения, которые было бы лучше предотвратить еще во время компиляции. Ну и, наконец, языки подготовки сценариев не являются объектно-ориентированными и потому не могут служить в качестве языков программирования высокого^ уровня, используемых для программирования больших систем. А вот огромным преимуществом ASP является то, что языки подготовки сценариев обычно очень легкие для1 изучения. В частности, VBScript известен огромному числу людей. То, что языки подготовки сценариев, подобные VBScript, не являются объектно-ориентированными, частично компенсируется их способностью вызывать серверные СОМ-компоненты. Дело в том, что эти компоненты можно писать на мощных объектно-ориентированных языках, таких, как C++. Другое преимущество ASP перед интерфейсом прикладного программирования Internet-сервера (ISAPI) состоит в том, что ASP прекрасно подходит для работы с сервером транзакций корпорации Microsoft (Microsoft Transaction Server, MTS). Это дает возможность автоматизировать организацию поточной обработки, а также управление синхронизацией, обработкой транзакций и безопасностью.
Технология ASP.NET, к счастью, сохраняет все преимущества традиционной ASP и избавлена от большинства ее недостатков, в том числе и снижения производительности. Вместо интерпретатора языков подготовки сценариев ASP.NET использует компилируемые языки платформы .NET, такие, например, как С#, VB.NET и даже управляемый C++.
Таким образом, теперь уже можно выбирать из нескольких технологий. Это общий шлюзовой интерфейс (CGI), интерфейс прикладного программирования Internet-сервера (ISAPI), ASP и ASP.NET. Ну да, есть еще и библиотека шаблонных классов ATL. Так же, как и ASP.NET, библиотека шаблонных классов ATL дает возможность разрабатывать как Web-узлы, так и Web-службы. Впрочем, серверы и службы на основе библиотеки шаблонных классов ATL создаются с помощью библиотеки шаблонов для C++, разработанной на основе технологии ISAPI (интерфейс прикладного программирования Internet-сервера).



Приложения на основе ATL Server

ATL Server (ATL-сервер) — это технология, использующая неуправляемый C++ и позволяющая в процессе разработки эффективно и без проблем применять интерфейс прикладного программирования Internet-сервера (ISAPI)[Библиотека шаблонных классов ATL в использовании удобнее, чем традиционный интерфейс прикладного программирования Internet-сервера (ISAPI), хотя и не может сравниться по удобству с ASP NET]. Так как интерфейс прикладного программирования Internet-сервера (ISAPI) традиционно используется в тех приложениях, где основным требованием является производительность, то не удивительно, что и в ATL Server предусмотрены те же преимущества в производительности.
Библиотека шаблонных классов ATL реализована в виде обычной библиотеки шаблонных классов для C++. Шаблоны в C++ имеют замечательное свойство: они позволяют определять новые классы на основе параметров, передаваемых компилятору. Благодаря такой возможности пользователи могут эффективно и гибко пополнять библиотеку классов.
Шаблон проекта ATL Server Project (Проект на основе ATL Server) содержит код пусковой системы для динамически подключаемой библиотеки (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI Extension DLL), которая через информационный сервер Internet (ПЗ) получает информацию из HTTP-запросов и сопровождающей Web-приложение динамически подключаемой библиотеки (DLL). Эта сопровождающая динамически подключаемая библиотека фактически реализует все необходимые для Web-приложения функциональные возможности.
Динамически подключаемые библиотеки (DLL) расширений интерфейса прикладного программирования Internet-сервера (ISAPI) и Web-приложений работают вместе с SRF-файлами (Server Request File — файлы запросов на обслуживание). В этих файлах содержится комбинация HTML-кода и простых дескрипторов сценариев или заглушек. Каждый такой файл содержит шаблон (не путать с шаблонами C++), предназначенный для создания Web-страницы для клиента. Эти страницы создаются путем замены заглушек, расположенных внутри двойных фигурных скобок. Каждой из заглушек дается имя, указывающее на функцию, которая реализуется динамически подключаемой библиотекой (DLL) Web-приложения. А при создании Web-страницы, которую надо передать клиенту в ответ на его запрос, каждая из этих функций генерирует фрагмент HTML-кода, подставляемый вместо дескриптора в двойных фигурных скобках.
Обычно при разработке Web-приложения на основе ATL Server большая часть времени уходит на вставку кода в динамически подключаемую библиотеку (DLL) этого приложения. Впрочем, имея исходный код, можно также делать изменения и в динамически подключаемой библиотеке (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI) (БАР1 Extension DLL). Но это может потребоваться только в том случае, когда нужно изменить грамматический разбор SRF-файла или обеспечить ту или иную фильтрацию HTTP-потока. Такой прием используется редко и является достаточно сложным.



ATL Server основан на интерфейсе прикладного программирования Internet-сервера (ISAPI)

Чтобы разобраться в ATL Server, очень важно вначале хорошо разобраться в теоретических основах интерфейса прикладного программирования Internet-сервера (ISAPI). Динамически подключаемая библиотека (DLL) интерфейса прикладного программирования Internet-сервера (ISAPI DLL) используется для фильтрации клиентских HTTP-запросов на входе/выходе информационного сервера Internet US (фильтр интерфейса прикладного программирования Internet-сервера (ISAPI)) или для динамической генерации HTML-кода, отправляемого клиенту в ответ на его запрос (расширение интерфейса прикладного программирования Internet-сервера (ISAPI)). И фильтры, и расширения интерфейса прикладного программирования Internet-сервера (ISAPI) используются для того, чтобы изменить или расширить обычное поведение информационного сервера Internet (US). Фильтры интерфейса прикладного программирования Internet-сервера (ISAPI) прекрасно подходят, в частности, для шифрования данных, мониторинга производительности и настройки системы опознавания. Что касается расширений интерфейса прикладного программирования Internet-сервера (ISAPI), то они прекрасно подходят для динамической генерации HTML-кода и для динамического преобразования в HTML-формат данных, не являющихся HTML-кодом — в частности, записей из базы данных. Например, расширение интерфейса прикладного программирования Internet-сервера (ISAPI) может отправлять запрос в базу данных и затем помещать полученные результаты в подходящим образом отформатированную HTML-страницу.



Архитектура приложения, использующего ATL server

Как и динамически подключаемые библиотеки (DLL) традиционных расширений интерфейса прикладного программирования Internet-сервера (ISAPI), динамически подключаемые библиотеки (DLL) расширений интерфейса прикладного программирования Internet-сервера (ISAPI) на основе библиотеки шаблонных классов ATL экспортируют функции GetExtensionVersion (получить версию расширения), HttpExtension-Proc (процедура HTTP-расширения) и TerminateExtension (завершить расширение). Кроме того, следуя традиционной манере, информационный сервер Internet (IIS) создает для каждого HTTP-запроса структуру EXTENSION_CONTROL_BLOCK (управляющий блок расширения). Она в качестве параметра передается в HttpExtensionProc. Эта структура обеспечивает доступ как к информации HTTP-заголовка, так и к потокам данных. Доступ к тому и другому нужен для поддержки связи с HTTP-клиентом.
Главной точкой входа для расширения интерфейса прикладного программирования Internet-сервера (ISAPI) является функция HttpExtensionProc. Она автоматически вызывается информационным сервером Internet (П5), если нужно обработать HTTP-запрос, который предназначен для расширения интерфейса прикладного программирования Internet-сервера (ISAPI) (ISAPI Extension). Для чтения клиентских данных и соответствующего реагирования HttpExtensionProc использует функции обратного вызова, предоставляемые параметром EXTENSION_CONTROL_BLOCK. На рис. 12.1 показана общая схема использования интерфейса прикладного программирования Internet-сервера (ISAPI) в Web-приложении, основанном на ATL Server.



Рис. 12.1. Архитектура приложения, основанного на ATL Server

На рис. 12.1 показана только одна динамически подключаемая библиотека (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI). Это сделано потому, что в каждом виртуальном каталоге-информационного сервера Internet (IIS) может быть только одна такая библиотека. Еще ла рисунке видно, что в виртуальном каталоге может быть несколько динамически подключаемых библиотек (DLL) Web-приложения и несколько . srf-файлов. И хотя код в динамически подключаемой библиотеке (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI) можно настраивать, все же это обычно делается в динамически подключаемых библиотеках (DLL) Web-приложений, потому что именно в этих библиотеках реализуются обработчики запросов.



Создание проекта ATL Server Project (Проект на основе ATL Server)

Чтобы с помощью ATL Server Project Wizard (Мастер создания проектов на основе ATL Server) создать проект ATL Server Project (Проект на основе ATL Server), нужно соблюдать определенную последовательность действий. Создать свой собственный проект вы можете либо выполнив указанные ниже действия, либо открыв в каталоге ATLServerApp (приложение на основе ATL Server) имеющееся в нем решение ATLServerApp.sin [В имеющемся решении находится также дополнительный код, который будет добавляться по мере чтения следующих нескольких страниц. ].

    Выберите следующие пункты меню: File => New => Project (Файл => Создать => Проект). В дереве Project Types (Типы проектов) откройте узел Visual C++ Projects (Проекты Visual C++). В окне Templates (Шаблоны) выберите ATL Server Project (Проект на основе ATL Server) [Обратите внимание, что в этом окне указан также шаблон ATL Server Web Service Project (Проект Web-службы на основе ATL Server) Выбор каждого из этих шаблонов приводит к появлению одного и того же мастера ATL Server Project Wizard (Мастер создания проектов на основе ATL Server), хотя и с небольшими отличиями. Этот мастер позволяет создать динамически подключаемую библиотеку DLL как для расширения интерфейса прикладного программирования Internet-сервера (ISAPI), так и для Web-приложения, но при выборе первого из указанных шаблонов задаются определенные значения параметров поддержки шаблона и проверки правильности Второй шаблон предназначен для создания проекта Web-службы, а не HTML-содержимого. ]. В качестве имени проекта введите ATLServerApp. Введите имя каталога, предназначенного для хранения проекта. В данном случае используется каталог Demos (Демонстрационные примеры). Для запуска Мастера создания проектов на основе ATL Server ATL Server Project Wizard щелкните на кнопке ОК. Перед тем как продолжать работу с этим мастером, просмотрите на ее вкладке Overview (Общие сведения) значения параметров, заданные по умолчанию. Кроме того, посмотрите на вкладки Project Settings (Параметры проекта), Server Options (Параметры сервера), Application Options (Параметры приложения) и Developer Support Options (Параметры поддержки разработчика). Они показаны на рисунках 12.2, 12.3, 12.4, 12.5 и 12.6. Не изменяя этих заданных по умолчанию значений, щелкните на кнопке Finish (Готово). На рис. 12.2 показана страница Overview (Общие сведения) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard). Информацию на этой вкладке можно изменить с помощью других вкладок, которые называются Project Settings (Параметры проекта), Server Options (Параметры сервера), Application Options (Параметры приложения) и Developer Support Options (Параметры поддержки разработчика)



Рис. 12.2. Вкладка Overview (Общие сведения) Мастера создания проектов на основе A TL Server (A TL Server Project Wizard)

Страница Project Settings (Параметры проекта) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard) показана на рис 12.3. Как обычно, можно изменить имя и расположение генерируемого проекта Кроме того, можно указать, следует ли генерировать динамически подключаемую библиотеку (DLL) Web-приложения (флажок Generate Web application DLL (Генерировать динамически подключаемую библиотеку (DLL) Web-приложения)). Эта библиотека реализует обработчик HTTP-запросов. Еще на данной странице можно указать, должно ли решение генерировать динамически подключаемую библиотеку (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI) (флажок Generate ISAPI extension DLL (Генерировать динамически подключаемую библиотеку (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI))). В этой библиотеке будет находиться код, предназначенный для отправки HTTP-запросов обработчику, расположенному в динамически подключаемой библиотеке (DLL) Web-приложения. Вы можете решить, надо ли объединять указанные два проекта в одну динамически подключаемую библиотеку (DLL) (флажок Generate combined DLL (генерировать объединенную динамически подключаемую библиотеку (DLL))). Ну и наконец, можно указать, надо ли генерировать автоматическую поддержку размещения, чтобы при создании вашего проекта автоматически выполнялась его установка на вашем Web-сервере (флажок Deployment support (Поддержка размещения)) [Атрибуты заставляют компилятор C++ вставлять тот или иной код в объектный файл ]. При выборе этой возможности можно указать виртуальный каталог, в котором должен быть установлен проект.



Рис. 12.3. Вкладка Project Settings (Параметры проекта) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard)

Страница Server Options (Параметры сервера) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard) показана на рис. 12.4. Она позволяет добавлять в динамически подключаемую библиотеку (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI) несколько возможностей, таких, например, как поддержка кэширования, счетчики производительности и поддержка состояния.
Страница Application Options (Параметры приложения) Мастера создания проектов на основе ATL Server из (ATL Server Project Wizard) показана на рис. 12 5. Она позволяет добавлять в динамически подключаемую библиотеку (DLL) Web-приложения несколько возможностей, таких, например, как проверка правильности параметров запроса и переменных формы, а также поддержка замены шаблонных дескрипторов. Эта страница дает также возможность указать, что проект следует создавать в виде Web-службы (флажок Create as Web Service (Создать в виде Web-службы)), а не в виде Web-узла.
Страница Developer Support Options (Параметры поддержки разработчика) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard) показана на рис. 12.6. Она позволяет управлять вставкой комментариев TODO (флажок Generate TODO comments (Генерировать комментарии TODO)), генерированием использующего атрибуты кода C++ [Чтобы работала автоматическая поддержка размещения, надо установить информационный сервер Internet (IIS). ] (флажок Attributed code (Код с атрибутами)), а также поддержкой обработки утверждений пользователя и трассировки (флажок Custom assert and trace handling support (Поддержка пользовательской обработки утверждений и трассировки)).



Рис. 12.4. Вкладка Server Options (Параметры сервера) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard)



Рис. 12.5. Вкладка Application Options (Параметры приложения) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard)



Рис. 12.6. Вкладка Developer Support Options (Параметры поддержки разработчика) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard)

Теперь посмотрите на код, который создан Мастером создания проектов на основе ATL Server (ATL Server Project Wizard) с использованием всех значений, установленных по умолчанию. Solution Explorer (Поиск решения) покажет, что в решении имеется два проекта. Это проекты двух динамически подключаемых библиотек (DLL) одна— для Web-приложения, а другая — для расширения интерфейса прикладного программирования Internet-сервера (ISAPI). В решении нет проекта размещения, но если взглянуть на параметры проектов, то можно увидеть, что проекты размещаются как раз во время их создания.

ATLServerAppIsapi — проект динамически подключаемой библиотеки (DLL) расширения интерфейса прикладного программирования Internet-сервера (IS API). ATLServerApp — проект динамически подключаемой библиотеки (DLL) Web-приложения.

Динамически подключаемая библиотека (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI)

В Solution Explorer (Поиск решения) откройте узел проекта ATLServerAppIsapi. Затем откройте файл ATLServerAppIsapi.def. Обратите внимание, что этот проект экспортирует три стандартные функции из динамически подключаемой библиотеки (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI). Вот эти функции.

HttpExtensionProc вызывается для каждого HTTP-запроса к расширению интерфейса прикладного программирования Internet-сервера (ISAPI). GetExtensionVersion вызывается; когда расширение интерфейса прикладного программирования Internet-сервера (ISAPI) загружается информационным сервером Internet (IIS). TerminateExtension вызывается, когда расширение интерфейса прикладного программирования Internet-сервера (ISAPI) выгружается информационным сервером Internet (IIS).

Кроме того, обратите внимание, что реализация каждой их этих функций находится в файле ATLServerAppIsapi.cpp. В каждом случае для работы с деталями просто используется объект theExtension. Типом данного объекта является ExtensionType, который определяется с помощью шаблона CIsapiExtension. Этот шаблон берет на себя всю скучную и вызывающую периодические ворчания работу, связанную с реализацией полнофункционального расширения интерфейса прикладного программирования Internet-сервера (ISAPI), в том числе и такие детали, как организация пула потоков и диспетчеризация запросов.

typedef CIsapiExtension <> ExtensionType;
// расширение ISAPI ATL Server ExtensionType theExtension;
// Делегировать экспорт ISAPI в theExtension
// extern "C"
DWORD WINAPI HttpExtensionProc (LPEXTENSION_CONTROL_
BLOCK IpECB)
{
return theExtension.HttpExtensionProc (IpECB}; }
extern "C"
BOOL WINAPI GetExtensionVersion (HSE_VERSION_INFO* pVer)
// ЛОГИЧЕСКИЙ МЕТОД
{
return theExtension.GetExtensionVersion (pVer); }
extern "C"
BOOL WINAPI TerminateExtension (DWORD dwFlags) // ЛОГИЧЕСКИЙ МЕТОД
{
return theExtension.TerminateExtension (dwFlags);
}

Структура EXTENSION_CONTROL_BLOCK, передаваемая в качестве параметра в показанную выше функцию HttpExtensionProc, содержит несколько примечательных членов. Самые важные члены этой структуры показаны в следующем определении типа. Конечно, проект ALTServerAppIsapi часто оставляют как он есть. И все же обратите внимание, что эту информацию об HTTP-запросе вполне можно использовать для выполнения нестандартной фильтрации.

typedef struct _EXTENSION_CONTROL_BLOCK {
HCONN ConnID; //in - уникальный номер от HTTP-сервера
DWORD dwHttpStatusCode; //out - состояние завершения
LPSTR IpszMethod; //in - требуемый метод
LPSTR IpszQueryString; //in - запрос информации
LPBYTE IpbData; //in - данные, посланные клиентом LPSTR IpszContentType; //in - совместимый тип данных
BOOL { WINAPI * WriteClient ) // записать ответ клиенту ( HCONN ConnID,
LPVOID Buffer, // Буфер LPDWORD IpdwBytes, DWORD dwReserved );
BOOL ( WINAPI * ReadClient ) // чтение запроса из HTTP ( HCONN ConnID, LPVOID IpvBuffer, LPDWORD IpdwSize );
} EXTENSION_CONTROL_BLOCK, *LPEXTENSION_CONTROL_BLOCK;



Динамически подключаемая библиотека (DLL) Web-приложения

Если в проекте динамически подключаемой библиотеки (DLL) Web-приложения вы откроете заголовочный файл ATLServerApp.h, то увидите определение класса CATLServerAppHandler. Атрибут request_handler (обработчик запросов) говорит о том, что класс будет открыт как обработчик запросов на основе ATL Server. Этот обработчик будет называться Default (Стандартный). В классе CATLServerAppHandler используется взятый для примера метод OnHello, имеющий атрибут tag_name (имя дескриптора), в котором указано имя Hello (Привет). Вскоре вы увидите, как эти атрибуты связаны с реальным клиентским запросом. Обратите внимание, насколько легко с помощью такого элемента данных, как m_HttpResponse (Http-ответ), отправлять клиенту данные, предназначенные для замены дескрипторов, используя для этого оператор вставки потока.

[ request_handler("Default") ] // По умолчанию class CATLServerAppHandler
{
private: // частный
// Поместить сюда частные элементы
protected: // защищенный
// Поместить здесь защищенные члены
public:
// Поместить здесь общедоступные члены
HTTP_CODE'ValidateAndExchange() {
// TODO: Put all initialization and validation ...
// TODO: Поместить весь код инициализации
// и проверки правильности...
// Установить совместимый тип
m_HttpResponse.SetContentType("text/html"); // текст/HTML
return HTTP_SUCCESS; }
protected: // защищенный
// Вот пример того, как использовать замену... [ tag_name(name="Hello") ] // Привет HTTP_CODE OnHello(void) {
m_HttpResponse « "Hello World!"; // Привет, мир!
return HTTP_SUCCESS;
}
};
// класс CATLServerAppHandler

Динамически подключаемая библиотека (DLL) Web-приложения работает вместе с .srf-файлом. На самом деле указанный файл является HTML-файлом, в котором могут находиться переменные дескрипторы данных, расположенные внутри двойных фигурных скобок. Эти дескрипторы являются заглушками, которые при обработке запроса будут заменяться процессором шаблонов библиотеки шаблонных классов ATL В каждую заглушку вставлен метод из того класса, который реализуется в динамически подключаемой библиотеке (DLL) Web-приложения.
Чтобы заглушкам в двойных скобках, находящимся в .srf-файлах, поставить в соответствие те или иные методы из динамически подключаемой библиотеки (DLL) вашего Web-приложения, в ATL Server предусмотрены необходимые для этого атрибуты. Каждый такой метод генерирует HTML-код, который должен заменять соответствующие дескрипторы заглушек из . srf -файла.
В Solution Explorer (Поиск решения) откройте узел проекта ATLServerApp, а затем откройте файл ATLServerApp.srf. Обратите внимание, что в этом файле содержатся текст и показанные внизу дескрипторы замены. Теперь сравните ATLServerApp. srf с кодом из показанного выше файла ATLServerApp.h. Вы должны заметить— класс CATLServerAppHandler помечен атрибутом request_handler как "Default" ("Стандартный"), что соответствует находящемуся внизу дескриптору обработчика, содержащему слово Default (Стандартный). Кроме того, данный дескриптор указывает имя динамически подключаемой библиотеки (DLL) Web-приложения, а именно ATLServerApp . dll. Это немаловажно, потому что в одном и том же виртуальном каталоге может находиться любое количество динамически подключаемых библиотек (DLL), относящихся к Web-приложению. В результате, для замены дескриптора этот . srf-файл будет использовать класс CATLServerAppHandler.
Кроме того, обратите внимание, что в показанном выше коде атрибут tag_name (имя дескриптора) указывает имя "Hello" ("Привет"). Данный дескриптор соответствует находящемуся внизу дескриптору из файла . srf, содержащему слово Hello (Привет). А это, в свою очередь, означает, что дескриптор Hello (Привет) будет заменен текстом, записанным выше в элемент данных m_HttpResponse с помощью метода OnHello [В одном . srf-файле для Web-приложения можно указывать больше одной динамически подключаемой библиотеки (DLL). Подробнее об этом говорится в документации по ATL Server ]. В коде пусковой системы, сгенерированном мастером, "Default" ("Стандартный") и "Hello" ("Привет") используются исключительно как примеры, которым мы можем следовать. А при добавлении своего собственного кода мы вполне можем для атрибутов обработчика запросов и атрибутов имен дескрипторов использовать какие-то другие, более значимые имена.

{{handler ATLServerApp.dll/Default}}
This is a test: {{Hello}}
({{обработчик ATLServerApp.dll/Default}}
Это - испытание: {{Привет}})



Создание и запуск проекта на основе ATL Server

Проект на основе библиотеки шаблонных классов ATL создается обычным способом. Во время создания окно вывода показывает, как происходит размещение проекта ATL-ServerApp. При этом размещении ATLServerApp. srf, ATLServerApp.dll и ATL-ServerAppIsapi.dll копируются в каталог \inetpub\wwwroot\ATLServerApp\. На рис. 12.7 показано приложение ATLServerApp сразу же после его размещения на информационном сервере Internet (IIS).
Затем можно посмотреть, что же получилось в результате Для этого следует запустить решение обычным способом в среде Visual Studio.NET или просто перейти в Web-броузере по адресу http:7/localhost/ATLServerApp/ATLServerApp.srf. Результат показан на рис. 12.8
Полезно с помощью отладчика понаблюдать, что же происходит в динамически подключаемой библиотеке (DLL) Web-приложения. Вы обнаружите, что в ATLServerAp-plsapi.dll сперва вызывается функция HttpExtensionProc с параметром EXTENSION_CONTROL_BLOCK, который содержит структуры, описанные в табл. 12.1. Содержимое этих элементов берется по адресу, определяемому унифицированным указателем информационного ресурса (URL), который указан в Web-броузере
Следующей вызывается функция ValidateAndExchange [На самом же деле для DLL_PROCESS_ATTACH следующей вызывается функция DllMain из ATLServerApp.dll При обработке Web-запросов DllMain вызывается несколько раз, и в настоящем контексте она будет игнорироваться Впрочем, обратите внимание, — этот первый вызов DllMain происходит потому, что динамически подключаемая библиотека DLL расширения интерфейса прикладного программирования Internet-сервера (1SAPI), ATLServerAppIsapi. dll, для обработки Web-запроса динамически загружает динамически подключаемую библиотеку (DLL) Web-приложения, ATLServerApp.dll ]. Она просто отправляет в HTTP-ответ, определенное значение, которое указывает тип содержимого (text/html) Кроме того, эта функция полезна тогда, когда инициализацию и проверку надо проводить перед обработкой запроса.
И, наконец, в динамически подключаемой библиотеке (DLL) Web-приложения вызывается метод OnHello класса CATLServerAppHandler. Этот метод отправляет в HTTP-ответ текст "Hello World!" ("Здравствуй, мир!"). Получившиеся в результате данные, которые передаются на броузер, можно увидеть, просматривая исходный текст HTML []. Комментарии вида <!— комментарий —> вставлены для удобства — Прим ред

<html>
<head>
</head>
<body> <!-- тело -->
This is a test: Hello World!<br>
<!-- Это - испытание: Привет, мир! -->
</body> <!-- тело -->
</html>



Рис. 12.7. Только что размещенное приложение ATLServerApp

Обратите внимание, что в .srf-файле указан метод-обработчик Default (Стандартный) в ATLServerApp. dll, а также дескриптор Hello (Привет), который будет заменен в результате подстановки, выполняемой динамически подключаемой библиотекой (DLL) Web-приложения

{{handler ATLServerApp.dll/Default}}
This is a test. {{Hello}}
({{обработчик ATLServerApp dll/Default}}
Это - испытание: {{Привет}})

В исходном коде указанной динамически подключаемой библиотеки (DLL) ATLServerApp.dll видно, что атрибут обработчика Default (Стандартный) применяется к классу CATLServerAppHandler, в котором содержится метод OnHello с атрибутом tag_name, соответствующим дескриптору Hello (Привет) Это означает, что когда информационный сервер Internet (US) получает запрос именно на этот . srf-файл, то, чтобы текстовая строка заменяла дескриптор, т е передавалась в ответ на запрос клиента, информационный сервер Internet (US) загружает указанную динамически подключаемую библиотеку (DLL), находит названный класс и вызывает указанный метод OnHello



Рис. 12.8. Просмотр стандартного файла ATLServerApp srf

Таблица 12.1. Структура EXTENSION_CONTROL_BLOCK для ATLServerApp.srf

Компонент структуры Значение
IpszMethod (метод) "СЕТ" (Получить)
IpszOueryString (строка запроса) " "
IpszPathlnf о (информация о пути) "/ATLServerApp/ ATLServerApp srf"
pbData (данные) 0

[ request_handler("Default") ] // по умолчанию
class CATLServerAppHandler
{
[ tag_name(name="Hello") ] // Привет
HTTP_CODE OnHello(void)
{
m__HttpResponse « "Hello World'"; // Привет, мир!
return HTTP_SUCCESS;
}


Добавление в сервер еще одного обработчика

Обработчик запросов, сгенерированный мастером ATL Server Wizard, предназначался только для того, чтобы показать вам, как можно писать свои собственные обработчики запросов Проанализируйте следующий код Он может служить простым примером добавления новых возможностей Этот код добавлен к ATLServerApp.h [Эти возможности также добавлены к имеющемуся примеру проекта ATLServerApp]. В новом коде класс обработчика запросов отмечен как "Another" ("Другой"), а метод замены — именем дескриптора "Time" ("Время")

// Другой обработчик, который добавлен к ATLServerApp
[request_handler("Another")] // Другой
class CAnotherATLServerAppHandler
{
protected: // защищенный
[ tag_name(name="Time") ] // Время
HTTP_CODE GetTheCurrentTime(void)
{
SYSTEMTIME systemTime;
GetLocalTime(SsystemTime);
m_HttpResponse
<< system!ime.wHour << ":" << systemTime.wMinute;
return HTTP_SUCCESS;
}
};



Рис. 12.9. Просмотр Another.srf

Как добавлять эти новые возможности к серверу, показывает файл Another .srf [К имеющемуся примеру проекта ATLServerApp добавлено несколько .srf-файлов. Все добавленные файлы будут описаны на нескольких следующих страницах. ]. Если вы добавите этот файл и заново создадите проект, то данный . srf-файл автоматически разместится вместе с остальной частью сервера. При просмотре Another. srf на Web-броузере можно увидеть отображение текущего времени. Вот содержимое файла

Another.srf.
{{handler ATLServerApp.dll/Another}} {{Time}} is the current time.
({{обработчик ATLServerApp.dll/Another}} {{Время}} - текущее время.)

Результат можно увидеть, перейдя по адресу http://localhost/ATLServerApp/ Another.srf. Кроме того, он показан на рис. 12.9.



Добавление на сервер обработки управляющей структуры if-else-endif

В файле if_else_endif. srf содержится управляющая структура if-else-endif (если-иначе-конец если). Аналогичный обработчик добавляется в динамически подключаемую библиотеку (DLL) Web-приложения. Обратите внимание, что если количество секунд четное, то возвращаемым значением является HTTP_SUCCESS (success — "успех"), а если нечетное, то возвращается HTTP_S_FALSE (false — "ложь"). S в HTTP_S_FALSE означает, что на самом деле это успешный (successful) код, и никакой ошибки нет. Вероятность каждого исхода составляет 50 %. Таким образом, если клиент выполнял обновление несколько раз, то оба указанных результата будут равномерно распределены. Обратите внимание, что метод ShouldThisBeDone ("должно ли это быть сделано") на самом деле никаких HTML-данных клиенту не отправляет. Он предназначен только для того, чтобы управлять размещением текста и дескрипторов между дескрипторами if (если), else (иначе) и endif (конец если), находящимися в . srf-файле. Вот код C++ для этих новых возможностей

// Обработчик для проверки if (если), else(иначе) и endif
[request_handler("if_else_endif")]
class C_if_else_endif_ATLServerAppHandler
{
protected: // защищенный
[ tag_name(name="ShouldThisBeDone") ]
HTTP_CODE ShouldThisBeDone(void)
{
SYSTEMTIME systemTime;
GetLocalTime(&systemTime);
// возвратить HTTP_SUCCESS в 50 % случаев
if (systemTime.wSecond % 2)
return HTTP_SUCCESS;
else
return HTTP_S_FALSE;
}
};

HTTP_SUCCESS и HTTP_S_FALSE в действительности представляют соответственно значения TRUE (ИСТИНА) и FALSE (ЛОЖЬ). Если вы в своем броузере укажете if_else_endif. srf и несколько раз обновите броузер, то увидите, что эти два исхода появляются в случайном порядке. И хотя в приоре такое не встречается, между дескрипторами if (если), else (иначе) и endif можно расположить другие дескрипторы

{{handler ATLServerApp.dll/if_else_endif}}
{{if ShouldThisBeDone}}
Here is text that is displayed if ShouldThisBeDone
{{else}}
Here is text that is displayed if *not* ShouldThisBeDone
{{endif}}

Вот более русифицированная версия.

{{обработчик ATLServerApp.dll/if_else_endif}}
{{если ShouldThisBeDone}}
Вот - текст, который отображается если ShouldThisBeDone
{{иначе}}
Вот - текст, который отображается если *не* ShouldThisBeDone
{{конец если}}

Результат можно увидеть, перейдя по адресу http://localhost/ATLServerApp/ if_else_endif.srf Два возможных исхода показаны на рис. 12.10. и 12.11.



Рис. 12.10. Просмотр if_else_endif.srf



Рис. 12.11. Другой просмотр if_else_endif.srf



Добавление на сервер обработки управляющей структуры while-endwhile

Следующий пример показывает использование цикла с условием окончания while-endwhile в соответствующем файле while_endwhile.srf Чтобы сохранить количество выполнений цикла, был добавлен компонент данных типа int, называемый count (счетчик) Этой переменной в конструкторе класса обработчика присваивается начальное значение, равное 0, а затем при каждом обращении к ShouldThisBeDoneAgain ("должно ли это быть сделано снова") значение count увеличивается на единицу Итерация продолжается до тех пор, пока выражение count <= 10 не станет ложным Обратите внимание, что в коде C++ на самом деле цикла с условием окончания while нет, а находится он в соответствующем . srf-файле Кроме того, в классе обработчика имеется два метода замены дескрипторов GetNextNumber (Получить следующее число) и GetNextNumberSquared (Получить квадрат следующего числа) Эти методы соответствуют двум дескрипторам из . srf-файла, появляющимся в цикле с условием окончания while

// Обработчик для проверки цикла с условием
// окончания while - endwhile
[request_handler("while_endwhile")]
class C_while_endwhile_ATLServerAppHandler
{
protected: // защищенный
int count; // счетчик
C_while_endwhile_ATLServerAppHandler() : count(0) // счетчик
{
}
[ tag_name(name="ShouldThisBeDoneAgain") ]
HTTP_CODE ShouldThisBeDoneAgain(void)
{
count++; // счетчик++;
if (count <= 10) // если (счетчик <= 10)
return HTTP_SUCCESS;
else
return HTTP_S_FALSE;
}
[ tag_name(name="GetNextNumber") ]
HTTP_CODE GetNextNumber(void)
{
m_HttpResponse
<< "The square of " << count << " is "; // Квадрат
//счетчика
return HTTP_SUCCESS;
}
[ tag_name(name="GetNextNumberSquared") ]
HTTP_CODE GetNextNumberSquared(void)
{
m_HttpResponse << count*count;
return HTTP_SUCCESS;
}
};

Соответствующий файл while_endwhile.srf отображает таблицу с числами и их квадратами В примере видно, что дескрипторы могут быть вложены так, как требуется Это приводит к тому, что дескрипторы GetNextNumber и GetNextNumberSquared заменяются несколько раз [Комментарии вида <!-- комментарий --> вставлены для удобства — Прим ред.].

<html>
<BODY> <!-- ТЕЛО -->
<Р>{{handler ATLServerApp.dll/while_endwhile}}</P> <!-- обработчик -->
<р>
<TABLE> <!-- таблица -->
{{while ShouldThisBeDoneAgain}}
<TR>
<TD>{{GetNextNumber}}</TD>
<TD>{{GetNextNumberSquared}}</TD>
</TR>
{{endwhile}}
</TABLE> <!-- таблица -->
</P>
</BODY> <!-- тело -->
</html>

Результат можно увидеть, перейдя по адресу http://localhost/ATLServerApp/while_endwhile. srf. Что получается при этом переходе, показано на рис. 12.12.



Рис. 12.12. Просмотр while_endwhile.srf



Передача параметров серверному обработчику

Файл pass_parameter. srf показывает, как можно передавать параметры методу замены обработчика запросов Web-приложения (pass parameter как раз и означает "передать параметр"). Класс обработчика запросов с помощью функций грамматического разбора преобразует первоначальные параметры, указанные в . srf-файле и имеющие строковый тип (string), в тот тип данных, который требуется методу обработчика запросов. В классе обработчика запросов сигнатура такого рода функции должна выглядеть следующим образом:

HTTP_CODE parSeFunction(
IAtlMemMgr* pMemoryManager,
LPCSTR szArgumentData,
parameterType** ppArgument);

Память, используемая для хранения преобразованного параметра, должна быть размещена с помощью pMemoryManager->Allocate (memory manager — "диспетчер памяти", allocate— "разместить"). Эту память не надо освобождать явным образом, потому что в нужное время она автоматически освобождается каркасом ATL Server. Исходные строковые (типа string) данные, передаваемые через параметр, выбираются из szArgumentData (данные аргумента). Преобразованный параметр передается методу обработчика запросов и затем сохраняется с помощью ppArgument (argument— "аргумент"). Для параметра вы можете определить свой собственный тип данных с помощью какой-либо структуры или использовать типы данных, указанные ниже .

bool (логический, булев); char (символ); unsigned char (символ без знака); short (короткий); unsigned short (короткий без знака); int; unsigned int (int без знака); _int64; unsigned_int64(_int64 без знака); double (с удвоенной точностью); float (с плавающей точкой).

Затем, как показано в следующей сигнатуре, аргумент принимается из класса обработки запросов соответствующим методом замены:

HTTP_CODE replacementMethod(
parameterType* pArgument);

Параметр pArgument должен указывать на тот тип данных, который используется в соответствующей функции грамматического разбора.
Связывать друг с другом метод замены и соответствующую ему функцию грамматического разбора можно с помощью одного из двух приемов. В соответствии с первым из них, если parameterType (тип параметра) является одним из типов, поддерживаемых для атрибута tag_name, то имя функции грамматического разбора можно пропускать, и она будет автоматически связываться с методом замены в результате учета типа.
Ну, а в соответствии со вторым приемом имя функции грамматического разбора, связываемой с методом замены, можно указывать явно в параметре parse_func (функция грамматического разбора) атрибута tag_name. Такой прием необходимо использовать тогда, когда вы с помощью какой-либо структуры определяете свой собственный тип параметра или имеются разные методы, которые принимают один и тот же тип параметра.
В следующем примере показана передача параметров из соответствующего файла pars_parameter .srf. Передача параметров выполняется с помощью первого из двух указанных приемов. В примере можно видеть, что передача параметра требует как функции грамматического разбора, так и метода замены.
Функция должна преобразовывать параметр из строкового типа в тот, который нужен (в данном примере это int) Что касается метода замены, то он должен принимать преобразованный параметр и управлять заменой дескрипторов.

// Обработчик для проверки передачи параметров
[request_handler("pass_parameter")]
class C_parameter_passing_ATLServerAppHandler
{
protected: // защищенный
// метод синтаксического анализа преобразовывает
// параметр из строки в int
HTTP_CODE parseFunction(
IAtlMemMgr* pMemoryManager,
LPCSTR szArgumentData,
int** ppArgument)
{
// распределить память для передаваемого параметра
int *pparam =
(int *)pMemoryManager->Allocate(sizeof(int) ) ;
// Распределить
// установить значение параметра, передаваемого
// методу замены *pparam = atoi(szArgumentData) ;
// передать параметр обратно через ppArgument
ppArgument = &pparam;
return HTTP_SUCCESS;
}
// метод замены принимает параметр типа int
[ tag_name(name="SquareOfParameter") ]
HTTP_CODE SquareOfParameter(int* pArgument)
{
m_HttpResponse
<< "Parameter was " // Параметр был
<< *pArgument << "<p>"
<< "Square of parameter is" // Квадрат параметра
<< *pArgument * *pArgument;
return HTTP_SUCCESS;
}
};

Квадрат параметра отображается соответствующим файлом pass_parameter.srf.

{{handler ATLServerApp.dll/pass_parameter}}
{{SquareOfParameter(10)}}

Результат можно увидеть, перейдя по адресу http://localhost/ATLServerApp/ pass_parameter.srf Что получается при этом переходе, показано на рис. 12.13.
Кроме того, из файла . srf в обработчик запросов Web-приложения можно передавать несколько параметров различных типов. Для этого надо определить структуру с элементами, которые должны соответствовать передаваемым параметрам Следующий пример демонстрирует, как из . srf-файла передаются два параметра Первый из них является числом, а второй — строкой Функция грамматического разбора выделяет указанные два параметра из одной строки и "укладывает" их в пользовательскую структуру, которая называется PARAMETER_DATA (данные параметров) Эта функция с помощью простых приемов грамматического разбора разбивает строку-параметр на лексемы и приводит тип каждого из параметров к тому типу, который должен быть у соответствующего элемента структуры Затем структура передается методу замены как один составной параметр.



Рис. 12.13. Просмотр pass_parameter srf

Данный пример также демонстрирует, как с помощью второго приема связать функцию грамматического разбора с указанным выше методом управления заменой В соответствии с этим приемом имя метода фа мм этического разбора явно указывается с помощью параметра parse_f unc в атрибуте tag_name метода замены

// Обработчик, который принимает два параметра
[request_handler("pass_two_parameters")]
class C_pass_two_parameters_ATLServerAppHandler
{
protected: // защищенный
// пользовательская структура для того,
// чтобы сохранять преобразованные параметры
typedef struct
{
short index; // короткий индекс
char string[100]; // строка символов
} PARAMETER_DATA;
// метод синтаксического анализа преобразовывает
// два параметра из строки
HTTP_CODE parseTwoParametersFunction(
IlAtlMemMgr* pMemoryManager,
LPCSTR szArgumentData,
PARAMETER_DATA** ppArgument)
{
// распределить память для параметров,
// которые будут переданы
PARAMETER_DATA *pparams =
(PARAMETER_DATA *)pMemoryManager->Allocate(
// Распределить
sizeof(PARAMETERJDATA));
// установить параметры, которые будут
// переданы методу замен
char *szToken = strtok( // символ
(LPSTR)szArgumentData, ", "); // получить 1-й параметр
pparams->index = atoi(szToken); // сохранить 1-й параметр
szToken = strtok(NULL, "\""); // ПУСТОЙ УКАЗАТЕЛЬ -
// пропустить пробелы, символы табуляции и пустой строки
szToken = strtok(NULL, "\""); // ПУСТОЙ"УКАЗАТЕЛЬ -
// получить 2-й параметр
strcpy(pparams->string, szToken); // строка - сохранить
// 1-й параметр
// передать параметры обратно через ppArgument
ppArgument = &pparams;
return HTTP_SUCCESS;
}
// метод замены принимает два параметра в структуру
[ tag_name(name="HandleTwoParameters",
parse_func="parseTwoParametersFunction") ]
HTTP_CODE HandleTwoParameters(PARAMETER_DATA* pArgument)
{
m_HttpResponse
<< "First parameter was " // Первый параметр был
<< pArgument->index << "<p>" // индекс
<< "Second parameter was \"" // Второй параметр был
<< pArgument->stnng << "\"<p>" // строка
<< "The ASCII code for this index is "
// Код ASCII для этого индекса
<< pArgument->string[pArgument->index] ;
return HTTP_SUCCESS;
}



Рис. 12.14. Просмотр pass_two_parameters.srf

Результат передачи двух параметров отображается с помощью соответствующего файла pass_two_parameters. srf (pass two parameters — "передать два параметра").

{{handler ATLServerApp.dll/pass_two_parameters}}
{{HandleTwoParametersdO, "here is a bit of text")}}

Этот результат можно увидеть, перейдя по адресу http://localhost/ATLServerApp/ pass_two_parameters .srf. Что получается при этом, показано на рис. 12.14.



Поддержка состояния сеанса

Протокол передачи гипертекстовых файлов HTTP — это протокол без установления соединения. Впрочем, ATL Server имеет возможность поддерживать для каждого клиента состояние сеанса между следующими друг за другом HTTP-запросами Это достигается с помощью cookie-файлов, предназначенных для сохранения данных о каждом клиентском сеансе. ATL Server может с помощью соответствующего cookie-файла получать данные о состоянии каждого клиентского сеанса.
Вначале cookie-файл создается расширением интерфейса прикладного программирования Internet-сервера (ISAPI). Он содержит пару, состоящую из имени и строкового значения. Затем эта пара передается клиенту в заголовке HTTP-ответа. Каждый cookie-файл дает возможность Web-серверу сохранять на Web-броузере тот или иной фрагмент информации, который впоследствии будет передаваться снова на сервер в заголовке каждого HTTP-запроса, направляемого по соответствующему унифицированному указателю информационного ресурса (URL).
Для удобства работы с cookie-файлами ATL Server предоставляет класс CCookie. Этот класс можно использовать для инкапсуляции cookie-файлов, содержащих одно значение или целый их набор.
Вот пример, который показывает, как сконструировать два простых метода замены, называемых SendCookieToClient (отправить cookie-файл клиенту) и GetCookieFromClient (получить cookie-файл от клиента). В примере используется cookie-файл с одним значением, который инкапсулирует имя nameOfCookie (имя cookie-файла) и значение, содержащее простое строковое представление текущего времени.

// Обработчик, который посылает cookie клиенту
[request_handler("send_cookie_to_client")]
class C_send_cookie_to_client_AppHandler
{
protected: // защищенный
[ tag_name(name="SendCookieToClient") ]
HTTP_CODE SendCookieToClient(void)
{
CString valueOfCookie;
SYSTEMTIME systemTime;
GetLocalTime(SsystemTime);
valueOfCookie.Format( // Формат
"%d:%d", systemTime.wHour, systemTime.wMinute);
CCookie cookie;
cookie.SetName("nameOfCookie");
cookie.SetValue(valueOfCookie);
cookie.SetPath("/"); //URL где применяется cookie
m_HttpResponse.AppendCookie(&cookie);
// указать, что мы послали cookie клиенту
m_HttpResponse
<< "SendCookieToClient sent: " // послать
<< valueOfCookie;
return HTTP_SUCCESS;
}
};
// Обработчик, который получает cookie от клиента
[request_handler("get_cookie_from_client")]
class C_get_cookie_from_client_AppHandler
{
protected: // защищенный
[ tag_name(name="GetCookieFromClient") ]
HTTP_CODE GetCookieFromClient(void)
{
CString valueOfCookie;
CCookie cookie =
m_HttpRequest.Cookies("nameOfCookie");
BOOL bSuccess = cookie.GetValue(valueOfCookie);
// ЛОГИЧЕСКОЕ ЗНАЧЕНИЕ
if (bSuccess)
{
// доказать, отображая cookie, что мы его получили
m_HttpResponse
<< "Proof that GetCookieFromClient worked: "
// <<"Доказательство, что работал
// GetCookieFromClient: "
<< valueOfCookie;
}
return HTTP_SUCCESS;
}

Соответствующие файлы send_cookie_to_client.srf и get_cookie_ f rom_client. srf взаимодействуют с Web-броузером для обмена информацией, которая хранится на клиентском компьютере в виде cookie-файла
Вначале Web-броузер получает доступ к файлу send_cookie_to_client. srf Этот srf-файл указывает метод замены, называемый SendCookieToClient, который создает и отправляет cookie-файл на Web-броузер

{{handler ATLServerApp.dll/send_cookie_to_client}}
{{SendCookieToClient}}

Затем Web-броузер получает доступ к файлу get_cookie_f rom_client. sr f А этот srf-файл указывает метод замены, называемый GetCookieFromClient, который, в свою очередь, принимает cookie-файл от клиента

{{handler ATLServerApp.dll/get_cookie_from_elient}}
{{GetCookieFromClient}}

Результат выполнения этого примера можно увидеть, перейдя вначале по унифицированному указателю информационного ресурса (URL) туда, откуда cookie-файл передается клиенту, а затем перейдя по унифицированному указателю информационного ресурса (URL) туда, куда cookie-файл передается от клиента Немного поэкспериментировав, вы увидите, что с cookie-файлом не происходит никаких изменений до тех пор, пока вы снова не перейдете по тому унифицированному указателю информационного ресурса (URL), откуда cookie-файл должен отправиться к клиенту Вот эти URL-адреса

http://localhost/ATLServerApp/send_cookie_to_client.srf, http://localhost/ATLServerApp/get_cookie_from_client.srf

Результат перехода в Internet Explorer по первому унифицированному указателю информационного ресурса (URL) показан на рис 12 15, а по второму — на рис. 12.16.



Рис. 12.15. Просмотр send_cookie_to_client srf.



Рис. 12.16. Просмотр get_cookie_from_chent srf

Это пример немного надуманный, но он прямо и просто показывает, каким образом работают cookie-файлы. Главное в нем — не реализм, а рабочий механизм таких файлов. В данном примере файл send_cookie_to_client. srf создает cookie-файл, содержащий текущее время, что было бы несколько необычно для приложения из реальной жизни. Затем файл get_cookie_from_client.srf отправляет HTML-код, который отображает содержимое cookie-файла, причем только как доказательство того, что этот файл работает Ну, так это и вовсе нетипично.
Более реалистичное приложение должно использовать cookie-файлы для хранения более полезной информации, такой, например, как предпочтения пользователя и нестандартные настройки страниц. Когда пользователь впервые посещает Web-страницу, то некоторую информацию можно получить с помощью формы. Получив информацию, сервер "укладывает" ее в один или несколько cookie-файлов и отправляет их на Web-клиент. Затем при последующих посещениях клиентом других страниц на том же самом Web-узле сервер может извлекать эти cookie-файлы, выбирать содержащуюся в них информацию и на ее основе настраивать генерируемый им HTML-код.



Получение доступа к переменным сервера

В этом примере показано, как получать доступ к серверной переменной HTTP_USER_AGENT (пользовательский HTTP-агент). Имеется еще несколько переменных сервера, которые вы также можете использовать.

// Обработчик (handler), который обращается к
// переменной сервера (access a server variable)
[request_handler ( "access_server_vanable") ]
class C_access_server_variable_AppHandler
{
protected: // защищенный
[ tag_name(name="AccessServerVariable") ]
HTTP_CODE AccessServerVariable(void)
{
// использовать переменную сервера HTTP_USER_AGENT
CString strUserAgent;
m_HttpRequest.GetUserAgent(strUserAgent) ;
m_HttpResponse
<< "I see that you are using: "
// <<"Я вижу, что вы используете: "
<< strUserAgent;
return HTTP_SUCCESS;
}
};

А вот связанный (associated) с этим кодом файл access_server_variable . srf (access server variable — "доступ к серверной переменной").

{ {handler ATLServerApp.dll/access_server_vanable}}
{{AccessServerVariable}}

На рис. 12.17. показан результат просмотра файла access_server_variable.srf, доступ к которому можно получить, перейдя по унифицированному указателю информационного ресурса (URL) http://localhost/ATLServerApp/access_server_variable.srf.



Рис. 12.17. Просмотр access_server_variable.srf



Обработка форм

В данном примере к ATLserverApp.h добавляется класс обработчика запросов, называемый C_process_post_AppHandler. В этом классе имеется метод ProcessPost, который получает доступ к переменной, переданной из формы с помощью объекта HTTP-запроса. Коллекцию CHttpRequestParams можно получить из метода CHttpRequest: :GetFormVars. Затем для получения из формы значения с определенным именем используется метод CHttpRequestParams :: Exchange В нашем примере таким именем значения является "txtName". Значение, содержащееся в szName, мы будем передавать назад клиенту — всего лишь для доказательства того, что этот метод работает.

// Обработчик (handler), который обрабатывает POST
[request_handler("process_post")]
class C_process_post_AppHandler
{
protected: // защищенный
[ tag_name(name="ProcessPost") ]
HTTP_CODE ProcessPost(void)
{
// использовать переменную формы
const CHttpRequestParams &request = // константа
m_HttpRequest.GetFormVars();
CValidateContext valCtx;
LPCSTR szName;
request.Exchange("txtName", SszName, fivalCtx); // запрос.
// Обмен
m_HttpResponse
<< "Welcome to ATL Server, " << szName << "<p>";
// «"Добро пожаловать в ATL Server,
" return HTTP_SUCCESS;
}
};

Вот файл process_post. srf, который предоставляет доступ к только что описанному методу ProcessPost:

{{handler ATLServerApp.dll/process_post}}
{{ProcessPost}}

На этот раз непосредственного доступа к process_post .srf через броузер не будет. Доступ теперь возможен через другой, HTML-файл, содержащий форму. Второй файл [При создании решения в среде Visual Studio html-файл автоматически копируется в виртуальный каталог размещения вместе с srf-файлами.] называется SimpleForm.html и содержит следующий HTML-код. Обратите внимание, что этот HTML-код регистрирует запрос, содержащий значение с именем "txtName".

<HTML>
<HEAD>
</HEAD>
<BODY> <!-- ТЕЛО -->
<form method="post" <!-- метод -->
action= <!-- действие -->
"http://localhost/ATLServerApp/process_post.srf">
Enter your name:
<!-- Введите ваше имя -->
<input name="txtName" type="text" size="30">
<!-- имя = "txtName" тип = "текстовый" размер = "30" -->
<input name="cmdEcho" type="submit" value="Echo">
<!-- входное имя = "cmdEcho" тип = "представить" значение =
// "Echo" -->
</form>
</BODY> <!-- тело -->
</HTML>

И опять же, будет полезно, используя отладчик, понаблюдать, что происходит внутри динамически подключаемой библиотеки (DLL) расширения интерфейса прикладного программирования Internet-сервера (ISAPI). Вы увидите, что функция HttpExtension-Proc из ATLServerAppIsapi . dll принимает параметр EXTENSION_CONTROL_BLOCK, который содержит данные, перечисленные в табл. 12.2. Содержимое этих элементов берется из формы, определяемой впоказанном выше файле SimpleForm.html.
В этом примере SimpleForm.html использует метод POST (ЗАПИСАТЬ), и данные переносятся в тело запроса. В классе обработчика доступ к этим данным выполняется с помощью массива FormVars (Переменные формы). Если файл SimpleForm.html был изменен для использования метода GET (ПОЛУЧИТЬ), тогда в строке запроса должны находиться данные [В элементе FORM (ФОРМА) атрибут метода может указывать один из двух методов отправки данных формы на Web-сервер, а именно GET (ПОЛУЧИТЬ) или POST (ЗАПИСАТЬ). Первый из них в конце универсального идентификатора ресурса (URI), указанного атрибутом действия элемента FORM (ФОРМА), вставляет знак вопроса, а затем — данные формы. Метод POST (ЗАПИСАТЬ) помещает эти данные в тело HTTP-запроса ]. Впрочем, массив FormVars также можно использовать для доступа к данным формы. В табл. 12.3 показаны значения параметра EXTENSION_ CONTROL_BLOCK в том случае, если бы элемент FORM (ФОРМА) был изменен для использования метода GET (ПОЛУЧИТЬ).
На рис. 12.18. показан файл SimpleForm.html с заполненной формой. Когда вы щелкнете на кнопке Echo (Эхо), то с помощью переменной формы осуществляется доступ к process_post. srf. Эта переменная содержит значение Bob (Боб). Результат показан на рис. 12.19.
Таблица 12.2. Структура EXTENSION_CONTROL BLOCK с указанием метода POST (ЗАПИСАТЬ)

Элемент структуры Значение
IpszMethod "POST" ("ЗАПИСАТЬ")
IpszQuerystring till
IpszPathlnfo "ATLServerApp/process_post.srf"
pbData "txtName=Bob&cmdEcho=Echo"

Таблица 12.3. Структура EXTENSION_CONTROL_BLOCK с указанием метода GЕТ (ПОЛУЧИТЬ)

Элемент структуры Значение
IpszMethod "GET" ("ПОЛУЧИТЬ")
IpszQuerystring "txtName=Bob&cmdEcho=Echo"
IpszPathlnfo "ATLServerApp/process_post.srf"
pbData 0



Рис. 12.18. Просмотр формы, которая находится в SimpleForm.htm



Рис. 12.19. Результат представления формы, которая находится в SimpleForm htm


Службы сеанса

Вы, возможно, помните рис 12 4, где показана страница Server Options (Параметры сервера) Мастера создания проектов на основе ATL Server (ATL Server Project Wizard) На этой странице имеется флажок Session services (Службы сеанса) Если установить такой флажок, то проект будет автоматически настроен на управление состоянием сеанса Доступ к переменным состояния сеанса обеспечивается классом CSessionStateService (Служба состояния сеанса) с помощью двух других классов CDBSession и CMemSes-sion Эти два класса, в свою очередь, реализуют интерфейс ISession, который определяет методы хранения, модификации, удаления и перечисления именованных переменных сеанса [Более подробно об управлении состоянием сеанса можно узнать в документации по ATL Server].



Создание проекта Web-службы на основе ATL Server (ATL Server Web Service Project)

В главе 11 "Web-службы" мы видели, как работают Web-службы, используя ASP NET Здесь не будет повторения теоретических основ их работы, ведь эти основы одни и те же, что бы ни использовалось для реализации Web-службы — ASP NET или ATL Server А вот что касается отличий, то главное из них состоит в том, что если ASP NET реализуется с помощью управляемого кода и допускает использование любого из языков платформы NET, то библиотека шаблонных классов ATL, наоборот, реализована с помощью неуправляемого кода и допускает использование только Visual C++
Вот последовательность действий, с помощью которых можно создать проект пусковой системы (стартера, или инициирующей программы) Web-службы на основе библиотека шаблонных классов ATL [Экземпляр решения для этого проекта имеется в каталоге ATLServerWeb ].

    Выберите следующие пункты меню File<=>NewOProject (ФайлОСоздать'ФПроект) В дереве Project Types (Типы проектов) откройте узел Visual C++ Projects (Проекты Visual C++) В окне Templates (Шаблоны) выберите ATL Server Web Service Project (Проект Web-службы на основе ATL Server) В результате появится Мастер создания проектов на основе ATL Server (ATL Server Project Wizard), причем предназначенный для создания Web-службы, а не Web-приложения В качестве имени проекта введите ATLServerWeb Введите имя каталога, предназначенного для хранения проекта В данном случае используется каталог Demos (Демонстрационные примеры) Для запуска Мастера создания проектов на основе ATL Server (ATL Server Project Wizard) щелкните на кнопке OK На вкладке Overview (Общие сведения) этой программы просмотрите значения параметров, заданные по умолчанию Кроме того, посмотрите на вкладки Project Settings (Параметры проекта), Server Options (Параметры сервера), Application Options (Параметры приложения) и Developer Support Options (Параметры поддержки разработчика) Они показаны на рис. 12.20, 12.21, 12.22, 12.23 и 12.24 Не изменяя этих заданных по умолчанию значений, щелкните на кнопке Finish (Готово) Выполняйте то, что обычно делается при создании проекта В результате на основе библиотеки шаблонных классов ATL будет создана и развернута Web-служба



Рис.12.20. Вкладка Overview (Общие сведения) Мастера создания Web-служб на основе библиотеки шаблонных классов ATL (ATL Web Service Project Wizard)



Рис. 12.21. Вкладка Project Settings (Параметры проекта) Мастера создания Web-служб на основе библиотеки шаблонных классов ATL (ATL Web Service Project Wizard)



Рис. 12.22. Вкладка Server Options (Параметры сервера) Мастера создания Web-служб на основе библиотеки шаблонных классов ATL (ATL Web Service Project Wizard)



Рис. 12.23. Вкладка Application Options (Параметры приложения) Мастера создания Web-служб на основе библиотеки шаблонных классов ATL (ATL Web Service Project Wizard)



Рис. 12.24. Вкладка Developer Support Options (Параметры поддержки разработчика) Мастера создания Web-служб на основе библиотеки шаблонных классов ATL (ATL Web Service Project Wizard)

Следующие файлы создаются только в проекте Web-службы на основе библиотеки шаблонных классов ATL. Файл обнаружения (discovery file) содержит информацию, отформатированную по правилам XML. Эта информация используется инструментами создания клиента для обнаружения функционального интерфейса, предоставляемого Web-службой. HTML-файл предоставляет доступ к читабельной (для людей!) информации о возможностях этой Web-службы.

.disco-файл. . htm-файл.

Ну а . srf-файл создается только в проекте на основе ATL Server (ATL Server project), а не в проекте Web-службы на основе библиотеки шаблонных классов ATL (ATL Web Service project), в котором он совсем ни к чему. Дело в том, что доступ к Web-службе выполняется не из Web-броузера, а из пользовательского клиентского приложения.
Единственный файл, который, хотя и имеется в проектах обоих видов, т.е. в проекте на основе ATL Server (ATL Server project) и в проекте Web-службы на основе библиотеки шаблонных классов ATL (ATL Web Service project), но при этом существенно отличается в зависимости от типа проекта, — это .h-файл, реализующий класс обработчика запросов ATL Server. В проектах обоих видов определяется пространство имен. Впрочем, только в проекте Web-службы на основе библиотеки шаблонных классов ATL (ATL Web Service project) пространство имен содержит интерфейс доступа к методам этой службы, а также класс обработчика запросов, имеющий дополнительный атрибут soap_handler. Кроме того, в этом классе есть метод из примера пусковой системы HelloWorld (Здравствуй, мир), к которому применяется атрибут soap_method.



Код Web-службы на основе ATL Server: ATLServerWebService.h

Главное, чем генерация Web-приложения отличается от генерации Web-службы, — это файл ATLServerWebService . h. В обоих случаях в этом файле определяется, хотя и с небольшим количеством отличий, класс обработчика запросов на основе ATL Server. В файле ATLServerWebService .h определяется также пространство имен и интерфейс доступа к Web-службе с помощью протокола SOAP. Вот код пусковой системы для этого файла. Обратите внимание, что в нем определяется интерфейс lATLServer-WebService. Именно этот интерфейс реализуется классом обработчика запросов, находящимся в одноименном исходном файле.

namespace ATLServerWebService
// пространство имен ATLServerWebService
{
// все структуры, перечисления и операторы typedef
// для вашей Web-службы должны быть размещены
// в этом пространстве имен
// IATLServerWebService - объявление интерфейса Web-службы
//
[
uuid("53A879FF-9D20-42A8-9978-COD4B05B10B7"),
object // объект
]
_interface lATLServerWebService // интерфейс
{
// HelloWorld - метод примера Web-службы на основе ATL Server.
//Он показывает, как объявить метод Web-службы, а также
// входные и выходные параметры
[id(1)] HRESULT HelloWorld( // идентификатор (1)
[in] BSTR bstrlnput, [out, retval] BSTR *bstrOutput);
// TODO: Add additional Web Service methods here
// TODO: Добавьте здесь дополнительные методы Web-службы
};
// ATLServerWebService - реализация Web-службы
//
[
request_handler(name="Default", // по умолчанию
sdl="GenATLServerWebWSDL") ,
soap_handler(
name="ATLServerWebService",
namespace="urn:ATLServerWebService", // пространство имен
protocol="soap" // протокол
)
]
class CATLServerWebService :
public lATLServerWebService
{
public:
// Это - пример метода Web-службы, который показывает как
// использовать атрибут soap_method, чтобы предоставить
// метод для использования как Web-метод
[ soap_method ]
HRESULT HelloWorld(
/*[in]*/ BSTR bstrlnput,
/*[out, retval]*/ BSTR *bstrOutput)
{
CComBSTR bstrOut(L"Hello "); // Привет
bstrOut += bstrInput;
bstrOut += L"!";
*bstrOutput = bstrOut.Detach();
return S_OK;
}
// TODO: Add additional Service methods here
// TODO: Добавьте здесь дополнительные методы Web-службы
};
// класс CATLServerWebService
}
// пространство имен ATLServerWebService

Создайте проект, а затем запустите его, как это обычно делается. В значениях свойств отладки проекта, установленных по умолчанию, задан унифицированный указатель информационного ресурса (URL) http://localhost/ATLServerWeb/ATLServerWeb .dll?Handler=GenATLServerWebWSDL. Результат просмотра этого унифицированного указателя информационного ресурса (URL) показан на рис. 12.25. При этом на самом деле никакие возможности Web-службы не вызываются. Просто на экран выводится XML-представление ее интерфейса.
Хотя просматривать эту страницу в броузере достаточно удобно, но такой способ доступа к Web-службе или ее использования нельзя назвать нормальным. Как правило, методы Web-службы вызываются клиентом из распределенного приложения. Чтобы увидеть, как это происходит, нам придется создать клиентскую программу, которая и будет делать такие вызовы.



Рис. 12.25. Просмотр в броузере проекта Web-службы на основе библиотеки шаблонных классов ATL (Web A TL Service Project).



Создание клиентской программы, обращающейся к Web-службе

Клиентская программа, которая обращается к Web-службе, может быть бого вида Сейчас мы создадим простую консольную клиентскую nporpai для тестирования только что созданной Web-службы на основе библиот шаблонных классов ATL [Эта клиентская программа имеется в каталоге ATLServerWebClient].

    Выберите следующие пункты меню. File^NewoProject (ФайлОСоздатьОПроект) В дереве Project Types (Типы проектов) откройте узел Visual C++ Projects (Проекты Visual C++) В окне Templates (Шаблоны) выберите Win32 Project (Проект Win32) В результате появится ATL Server Project Wizard (Мастер создания проектов на основе ATL Server) В качестве имени проекта введите ATLServerWebChent Введите подходящее имя каталога, предназначенного для хранения проекта Для запуска Мастера создания проектов Win32 (Win32 Project Wizard) щелкните на кнопке ОК На вкладке Application Settings (Параметры приложений) Мастера создания проектов Win32 (Win32 Project Wizard) выберите переключатель Console application (Консольное приложение) Щелкните на кнопке Finish (Готово). В Solution Explorer (Поиск решения) щелкните правой кнопкой мыши на узле ATLServerWebChent В контекстном меню выберите пункт Add Web Reference (Добавить Web-ссылку) В диалоговом окне Add Web Reference (Добавить Web-ссылку) укажите унифицированный указатель информационного ресурса (URL) для ATLServerWeb disco [При создании проекта Web-службы на основе библиотеки шаблонных классов ATL файл обнаружения был автоматически размешен в соответствующем виртуальном каталоге информационного сервера Internet (IIS) ] — файла обнаружения Web-службы на основе библиотеки шаблонных классов ATL (рис 12 26) Затем щелкните на кнопке Add Reference (Добавить ссылку) В клиентский проект будет добавлен файл исходного кода ATLServerWeb. h, который реализует объект- заместитель, предназначенный для вызова методов Web-службы [При изменении серверного интерфейса это действие надо повторить чтобы сгенерировать для клен-та новый заместитель]. Откройте файл исходного кода ATLServerWebClient. cpp и вставьте в него код, выделенный полужирным шрифтом

#include "stdafx.h"
#define _WIN32_WINNT 0x0400 // нужна _WIN32_WINNT >= 0x0400
#include "ATLServerWeb.h" // необходимо обратиться к прокси-серверу
int _tmain(int argc, _TCHAR* argv[])
{
Colnitialize(NULL); // ПУСТОЙ УКАЗАТЕЛЬ
ATLServerWebService::CATLServerWebServiceTO service; // служба
CComBSTR bstrInput(L"ATL Web Service");
// Web-служба на основе ATL
CComBSTR bstrOutput;
service.HelloWorId(bstrlnput, SbstrOutput); // служба
wprintf(
L"HelloWorld returned bstrOutput: %s\n",
bstrOutput);
return 0;
}



Рис. 12.26. Добавьте Web-ссылку в ATLServerWeb disco

    Создайте проект клиента Web-службы на основе библиотеки шаблонных класов ATL и запустите его так, как это обычно делается Затем запустите программ, и тогда вы сможете увидеть следующий результат

HelloWorld returned bstrOutput Hello ATL Web Service !



Добавление функций в Web-службу на основе ATL Server

Вы, может быть, помните пример SimpleWebService из главы 11 "Web службы", всо-тором выполнялось сложение двух чисел Похожие возможности мы сейчас добавм в проект ATLServerWeb, только что созданный в этой главе Итак, мы добавим метод, к<го-рый принимает два целых параметра и возвращает их сумму Чтобы добавить ноую функцию, просто выполните указанную последовательность действий

    Откройте только что созданное решение ATLServerWeb sin В файл ATLServerWeb.h вставьте определение метода Add (Сложить) в инер-фейс lATLServerWebService, как показано полужирным шрифтом [В уже существующем методе HelloWorld значение диспетчерского идентификатора установленоэав-ным 1 В этом примере диспетчерские идентификаторы не используются но если вы очень хотите |ри-своить диспетчерский идентификатор новому методу Add (Сложить) то должны использовать слеую-щее доступное число, каким должно быть число 2].

_interface lATLServerWebService // интерфейс
{
// TODO: Add additional Web Service methods here
// TODO: Добавьте здесь дополнительные методы Web-службы
HKESULT Add( // Сложить
[in] long x, [in] long y, [out, retval] long *psum);
};

    В том же файле ATLServerWeb. h вставьте, как показано полужирным шрифтом, реализацию метода Add (Сложить) в класс CATLServerWebService

class CATLServerWebService :
public IATLServerWebService
{
public:
// TODO. Add additional Service methods here
// TODO: Добавьте здесь дополнительные методы Web-службы
[ soap_method ]
HRESULT Add(long x, long y, long *psum)
{
*psum = x + y;
return S_OK;
}
}; // класс CATLServerWebService

    Создайте проект [Перейдя в своем броузере по адресу http //localhost/ATLServerWeb/ ATLServerWeb dll"> Handler=GenATLServerWebwSDL, вы увидите, что появилась новая информация— о методе Add (Сложить)].

Теперь сервер готов для доступа к нему с любой клиентской программы, которая передает на сервер два целых параметра, а с него получает один параметр, и тоже целый



Изменение клиентской программы, работающей с Web-службой

Теперь вам, возможно, захочется с помощью клиентской программы протестировать метод Add (Сложить) Для этого выполните указанную последовательность действий

    Откройте уже созданный проект ATLServerWebClient sin Снова добавьте в проект Web-ссылку http //localhost/ATLServerWeb/ ATLServerWeb disco Это делается в пункте меню Project => Add Web Reference (Проект => Добавить Web-ссылку) Такая операция уже проводилась, но сейчас ее надо повторить из-за изменений, только что сделанных в интерфейсе сервера Таким образом будет заново создан заместитель, используемый клиентом для доступа к новому методу Add (Сложить) [В результате создается новый заголовочный файл, реализующий клиентский заместитель Чтобы получить доступ к этому новому заголовочному файлу, вам придется дать ему имя старого файла или изме нить директиву #include.]. Откройте файл ATLServerWebClient cpp и вставьте в него код, выделенный полужирным шрифтом

int _tmain(int argc, _TCHAR* argv[]) {
Colnitialize(NULL); // ПУСТОЙ УКАЗАТЕЛЬ
int sum; // сумма
service.Add(3, 4, &sum); // служба.Сложить
wprintf(
L"The result of calling Add(3, 4) is: %d\n",
//резуьтат вызова Сложить
sum); // сумма
return 0 ;
}

    Создайте клиентский проект и запустите его. Вы сможете увидеть следующий результат:

The result о f calling Add ( 3, 4) is: 7

Вот перевод:

Результат вызова Сложить (3, 4): 7



Передача структур в качестве входных и выходных параметров

Вот простой пример того, как метод Web-службы может использовать структуры в качестве входных и выходных параметров. В исходный файл ATLServerWeb.h была добавлена структура MyStructure (Моя структура), содержащая два элемента типа int. Кроме того, в интерфейс IATLServerWebService был добавлен новый метод CopyMyStructure (Копировать мою структуру), который в качестве параметров передает в MyStructure указатели и принимает их от нее. Затем данный метод реализуется в классе CATLServerWebService.

namespace ATLServerWebService
// пространство имен ATLServerWebService
{
struct MyStructure
{
int x;
int y;
};
[
uuid("53A879FF-9D20-42A8-9978-COD4B05B10B7") ,
object / / объект
]
interface IATLServerWebService // интерфейс
{
HRESULT CopyMyStructure (
[in ] MyStructure *pms1, [out ] MyStructure *pms2);
};
class CATLSeir-verWebService :
public IATLServerWebService
{
public:
[ soap me tihod ]
HRESULT CopyMyStructure(
MyStructure *pms1, MyStructure *pms2)
{
pms2->x = pms1->x;
pms2->y = pms1->y;
return S_OK;
}
};

А вот клиентский код, который проверяет передачу входных и выходных параметров.

// передача указателей на структуры
// в качестве входных и выходных параметров
struct ATLServerWebService: -.MyStructure msl, ms2;
ms1.x = 10;
msl.у = 20;
ms2.x = 0;
ms2.y = 0;
wprintf(
L"ms1.x: %d, ms1.y: %d, ms2.x: %d, ms2.y: %d\n",
ms1.x, ms1.y, ms2.x, ms2.y);
wprintf(
L"Calling CopyMyStructure(&ms1, &ms2)\n",
ms2.x, ms2.y);
service.CopyMyStructure ( // служба
&ms1,
sizeof (ATLServerWebService::MyStructure) ,
&ms2);
wprintf(
L"ms1.x: %d, ms1.y: %d, ms2.x: %d, ms2.y: %d\n",
ms1.x, ms1.y, ms2.x, ms2.y);

Приводимая далее выдача программы доказывает, что маршализация структуры может выполняться в обоих направлениях. Вначале элементы х и у структуры ms2 содержат нулевые значения. Во время вызова метода CopyMyStructure структура ms2 изменяется, поскольку элементы копируются из msl, а затем ms2 передается обратно клиенту.

msl.x: 10, msl.y: 20, ms2.x: 0, ms2.y: 0
Calling CopyMyStructure(&msl, &ms2)
msl.x: 10, msl.y: 20, ms2.x: 10, ms2.y: 20

Сейчас вас, возможно, удивит, зачем было затевать столько работы. И чем это все лучше предоставления функций в виде динамически подключаемой библиотеки (DLL) или вызова удаленных процедур (RFC — Remote Procedure Call) или распределенной модели компонентных объектов (DCOM — Distributed Component Object Model)? Так вот, "крутизна" Web-службы как раз в том, что она, в отличие от динамически подключаемой библиотеки (DLL), может находиться в любом месте Internet. Кроме того, Web-службы, в отличие от вызова удаленных процедур (RFC — Remote Procedure Call) или распределенной модели компонентных объектов (DCOM — Distributed Component Object Model), создаются на основе языка XML и SOAP. В дальнейшем это позволит вам применять некоторые интересные возможности, связанные с интеграцией.



Резюме

Web-службы позволяют создавать крупномасштабные распределенные приложения, которые могут использовать вездесущую природу Internet Эти службы строятся на основе стандартных и повсеместных протоколов, таких, как HTML, XML и SOAP, поэтому они значительно более гибки и естественны, чем построенные на основе традиционных распределенных компьютерных технолошй, таких, например, как вызов удаленных процедур (RFC — Remote Procedure Call) Библиотека шаблонных классов ATL предоставляет возможности для создания Web-служб, и благодаря своей эффективности является идеальным средством для реализации тех Web-служб, от которых требуется высокая производительность